﻿using Qy.Core;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;

namespace Qy.Scenario;
public class QyRepository<T> : SimpleClient<T> where T : class, new()
{
    //public ITenant itenant = null;//多租户事务

    private readonly ApplicationContext _applicationContext;
    public QyRepository(ApplicationContext applicationContext, ISqlSugarClient context = null) : base(context)
    {
        var configId = typeof(T).GetCustomAttribute<TenantAttribute>()?.configId;
        if (configId != null)
            Context = DbScoped.SugarScope.GetConnectionScope(configId);//根据类传入的ConfigId自动选择
        else
            Context = context ?? DbScoped.SugarScope.GetConnectionScope(0);//没有默认db0        
        _applicationContext = applicationContext;

        //itenant = DbScoped.SugarScope;//设置租户接口
    }

    public static string GetEntityFullName()
    {
        Type t = typeof(T);
        return t.FullName;
    }
    private static string GetEntityCacheKeyAll()
    {
        return GetEntityFullName() + "_list_all";
    }

    public virtual async Task OnRemoveListAllAsync()
    {
        await _applicationContext.ICacheManager.RemoveAsync(GetEntityCacheKeyAll());
    }

    #region query
    public ISugarQueryable<T> Queryable()
    {
        return Context.Queryable<T>();
    }
    /// <summary>
    /// 根据主值查询单条数据
    /// </summary>
    /// <param name="pkValue">主键值</param>
    /// <returns>泛型实体</returns>
    public async Task<T> GetIdAsync(object pkValue)
    {
        return await Context.Queryable<T>().InSingleAsync(pkValue);
    }
    /// <summary>
    /// 根据条件查询分页数据
    /// </summary>
    /// <param name="where"></param>
    /// <param name="parm"></param>
    /// <returns></returns>
    public async Task<PagedInfo<T>> GetPagesAsync(int pageNum, int pageSize)
    {
        PagerInfo page = new()
        {
            PageSize = pageSize,
            PageNum = pageNum
        };
        ISugarQueryable<T> source = Context.Queryable<T>();
        return await source.ToPageAsync(page);
    }
    public PagedInfo<T> GetPages(Expression<Func<T, bool>> where, PagerInfo parm, Expression<Func<T, object>> order, OrderByType orderEnum = OrderByType.Asc)
    {
        ISugarQueryable<T> source = Context.Queryable<T>()
            .Where(where).OrderByIF(orderEnum == OrderByType.Asc, order, OrderByType.Asc)
            .OrderByIF(orderEnum == OrderByType.Desc, order, OrderByType.Desc);
        return source.ToPage(parm);
    }
    /// <summary>
    /// 查询所有数据并缓存
    /// </summary>
    /// <param name="orderBy">排序</param>
    /// <param name="cacheTimeSeconds">缓存时间 默认为30天=2592000秒</param>
    /// <returns></returns>
    public async Task<List<T>> GetAllListAsync(string orderBy, int cacheTimeSeconds = 2592000)
    {
        List<T> list = await _applicationContext.ICacheManager.GetAsync<List<T>>(GetEntityCacheKeyAll());
        if (list == null)
        {
            list = await Context.Queryable<T>().OrderBy(orderBy).ToListAsync();
            _applicationContext.ICacheManager.Set(GetEntityCacheKeyAll(), list, TimeSpan.FromHours(cacheTimeSeconds));
        }
        return list;
    }

    #endregion query


    #region add

    public async Task<int> AddReturnIdAsync(T t, bool ignoreNull = true)
    {
        return await Context.Insertable(t).IgnoreColumns(ignoreNullColumn: ignoreNull).ExecuteCommandAsync();
    }

    public virtual async Task<int> InsertReturnIdAsync(T t)
    {
        return await Context.Insertable(t).ExecuteReturnIdentityAsync();
    }

    public virtual async Task<T> InsertAndDelCacheAsync(T t)
    {
        T x = await Context.Insertable(t).ExecuteReturnEntityAsync();
        if (x != null)
            await OnRemoveListAllAsync();
        return x;
    }

    public int BatchInsert(List<T> t)
    {
        return Context.Insertable(t).ExecuteCommand();
    }
    public virtual async Task<int> BatchInsertBaseAsync(List<T> t)
    {
        return await Context.Insertable(t).ExecuteCommandAsync();
    }

    #endregion add

    #region update
    public async Task<int> UpdateAsync(T entity, bool ignoreNullColumns = false)
    {
        return await Context.Updateable(entity).IgnoreColumns(ignoreNullColumns).ExecuteCommandAsync();
    }

    public async Task<int> UpdateAndDelCacheAsync(T entity, bool ignoreNullColumns = false)
    {
        int x = await Context.Updateable(entity).IgnoreColumns(ignoreNullColumns).ExecuteCommandAsync();
        if (x > 0)
        {
            await OnRemoveListAllAsync();
        }
        return x;
    }
    #endregion update

    #region delete
    /// <summary>
    /// 批量删除
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public async Task<int> DeleteAsync(object[] obj)
    {
        return await Context.Deleteable<T>().In(obj).ExecuteCommandAsync();
    }
    /// <summary>
    /// 按主键删除并删除缓存
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public virtual async Task<int> DeleteAndDelCacheAsync(object id)
    {
        int x = await Context.Deleteable<T>(id).ExecuteCommandAsync();
        if (x > 0)
            await OnRemoveListAllAsync();
        return x;
    }

    public async Task<int> DeleteAsync(object id)
    {
        return await Context.Deleteable<T>(id).ExecuteCommandAsync();
    }
    #endregion delete
}

/// <summary>
/// 分页查询扩展
/// </summary>
public static class QueryableExtension
{
    /// <summary>
    /// 读取列表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">查询表单式</param>
    /// <param name="parm">分页参数</param>
    /// <returns></returns>
    public static PagedInfo<T> ToPage<T>(this ISugarQueryable<T> source, PagerInfo parm)
    {
        PagedInfo<T> page = new();
        int total = 0;
        page.PageSize = parm.PageSize;
        page.PageIndex = parm.PageNum;

        page.Result = source.OrderByIF(parm.Sort.IsNotEmpty(), $"{parm.Sort.ToSqlFilter()} {(parm.SortType.Contains("desc") ? "desc" : "asc")}")
            .ToPageList(parm.PageNum, parm.PageSize, ref total);
        page.TotalNum = total;
        return page;
    }

    public static async Task<PagedInfo<T>> ToPageAsync<T>(this ISugarQueryable<T> source, PagerInfo parm)
    {
        PagedInfo<T> page = new();
        RefAsync<int> total = 0;
        page.PageSize = parm.PageSize;
        page.PageIndex = parm.PageNum;

        page.Result = await source.OrderByIF(parm.Sort.IsNotEmpty(), $"{parm.Sort.ToSqlFilter()} {(parm.SortType.Contains("desc") ? "desc" : "asc")}")
            .ToPageListAsync(parm.PageNum, parm.PageSize, total);
        page.TotalNum = total;
        return page;
    }
}
